Web SDK
Stoker provides a Web SDK that can be used to work with your app.
The Admin UI uses this SDK under the hood.
Installation
npm i @stoker-platform/web-client
Utilities
All web helper functions are available in the Web SDK.
initializeStoker
Initialize a Stoker app.
(
config: any,
collectionFiles: any,
envVars: Record<string, string>,
context?: any
) => Promise<boolean>
Parameters
config: Imported global config file. For example: await import("config/main")
collectionFiles: Imported collection config files. For example (Vite): await import.meta.glob("config/collections/*", { eager: true })
envVars: Env vars. For example (Vite): import.meta.env
context: State and helper functions that will be passed to the global and collection config files.
Returns
A boolean indicating whether a user is logged in.
authenticateStoker
Authenticate a user.
(
email: string,
password: string,
getMultiFactorTOTP?: () => Promise<string>
) => Promise<void>
getMultiFactorTOTP: A promise that will be fired when MFA is required. This promise should display an OTP field and return the users OTP (one-time-password).
onStokerReady
(callback: () => unknown) => () => void
Fires when the user has successfully authenticated and Stoker is ready.
Returns a listener removal function.
signOut
() => Promise<void>
Sign out the currently authenticated user.
onStokerSignOut
(callback: () => unknown) => () => void
Fires when the user has successfully signed out.
Returns a listener removal function.
onStokerPermissionsChange
(callback: () => unknown) => () => void
Fires when the currently authenticated user's permissions have changed.
Returns a listener removal function.
multiFactorEnroll
Enroll the currently authenticated user in MFA.
(
user: User,
getMultiFactorCode: (secret: string, totpUri: string) => Promise<string>
) => Promise<void>
user: The Firebase user for the currently logged in user. Can be retrieved using getCurrentUser.
getMultiFactorCode: A promise that provides a secret and a TOTP URI and must return a OTP (one-time-password).
addRecord
Add a record to the database.
(
path: string[],
data: Partial<StokerRecord>,
user?: {
password: string
passwordConfirm: string
permissions?: StokerPermissions
},
options?: {
retry?: { type: string; docId: string }
},
id?: string,
onValid?: () => void,
) => Promise<StokerRecord>
Parameters
path: The path to the collection for the record i.e. ["Clients"]. If the record will be in a subcollection, the path will look more like ["Clients", "D89X6ZQ1sclE71BfsWmv", "Sites"].
data: The record to save.
user: Optional user credentials, if this collection has auth enabled. Permissions must be provided in this structure:
type StokerPermissions = {
Role?: string
Enabled?: boolean
collections?: {
[collection: string]: {
auth?: boolean
operations: ("Read" | "Create" | "Update" | "Delete")[]
recordOwner?: {
active: boolean
}
recordUser?: {
active: boolean
}
recordProperty?: {
active: boolean
}
restrictEntities?: boolean
individualEntities?: string[]
parentEntities?: string[]
parentPropertyEntities?: Record<string, string[]>
}
}
}
options: For internal use.
id: Optionally provide a Firestore id for the new record.
onValid: A callback that will fire when the record has passed validation.
Returns
The saved record.
updateRecord
Update a record in the database.
You only need to provide the fields that you want to update.
To delete a field, provide a Firestore delete sentinel
You can transactionally increment or decrement a field value
The originalRecord value provided to hooks in the Web SDK may be stale. If you need the latest value for originalRecord, you'll need to set access.serverReadOnly.
(
path: string[],
docId: string,
data: Partial<StokerRecord>,
user?: {
operation: "create" | "update" | "delete"
password?: string
passwordConfirm?: string
permissions?: StokerPermissions
},
options?: {
retry?: { type: string; originalRecord: StokerRecord }
},
originalRecord?: StokerRecord,
) => Promise<StokerRecord>
Parameters
path: The path to the collection for the record i.e. ["Clients"]. If the record is in a subcollection, the path will look more like ["Clients", "D89X6ZQ1sclE71BfsWmv", "Sites"].
docId: The id of the record to update.
data: The data to update.
user: Optional user credentials, if this collection has auth enabled. Permissions must be provided in the structure defined in addRecord above. Use operation to specify whether credentials should be added, updated or deleted.
options: For internal use.
originalRecord: Provide the existing record where applicable to improve performance. If this is not provided, the existing record will be retrieved from the database / cache.
Returns
The updated record.
deleteRecord
Delete a record from the database.
(
path: string[],
docId: string,
options?: { retry?: { type: string; record: StokerRecord } },
) => Promise<StokerRecord>
Parameters
path: The path to the collection for the record i.e. ["Clients"]. If the record is in a subcollection, the path will look more like ["Clients", "D89X6ZQ1sclE71BfsWmv", "Sites"].
docId: The id of the record to delete.
options: For internal use.
Returns
The deleted record.
getOne
Retrieve a record from the database.
(
path: string[],
docId: string,
options?: {
only?: "cache" | "server";
relations?: {
fields?: (string | CollectionField)[];
depth: number;
};
subcollections?: {
collections?: string[];
depth: number;
constraints?: QueryConstraint[];
limit?: {
number: number;
orderByField: string;
orderByDirection: "asc" | "desc";
};
};
noComputedFields?: boolean;
noEmbeddingFields?: boolean;
}
) = Promise<StokerRecord>
Parameters
path: The path to the collection for the record i.e. ["Clients"]. If the record is in a subcollection, the path will look more like ["Clients", "D89X6ZQ1sclE71BfsWmv", "Sites"].
docId: The id of the record to retrieve.
options.only: Only query the cache or the server.
options.relations: Include related records. Specify the depth to retrieve relations for. Optionally specify a subset of relation fields to retrieve.
options.subcollections: Include records from the record's subcollections. Optionally specify a subset of subcollections to retrieve. Optionally provide Firestore where() query constraints to apply to subcollection queries. Optionally limit the number of results and specify results sorting.
options.noComputedFields: Exclude computed fields from the record.
options.noEmbeddingFields: Exclude embeddings fields from the record.
Returns
The record.
getSome
Retrieve multiple records from the database.
(
path: string[],
constraints?: QueryConstraint[] | [string, WhereFilterOp, unknown][],
options?:
{
only?: "cache" | "server"
relations?: {
fields?: (string | CollectionField)[]
depth: number
}
subcollections?: {
collections?: string[]
depth: number
constraints?: QueryConstraint[]
limit?: {
number: number
orderByField: string
orderByDirection: "asc" | "desc"
}
}
pagination?: {
number: number
orderByField?: string | FieldPath
orderByDirection?: "asc" | "desc"
startAfter?: Cursor
endBefore?: Cursor
}
noEmbeddingFields?: boolean
noComputedFields?: boolean
}
) => Promise<{
cursor: Cursor;
pages: number | undefined;
docs: StokerRecord[];
}>
Parameters
path: The path to the collection for the records i.e. ["Clients"]. If the records are in a subcollection, the path will look more like ["Clients", "D89X6ZQ1sclE71BfsWmv", "Sites"].
constraints: Provide Firestore where() query constraints to the query.
options.only: Only query the cache or the server.
options.relations: Include related records. Specify the depth to retrieve relations for. Optionally specify a subset of relation fields to retrieve.
options.subcollections: Include records from each record's subcollections. Optionally specify a subset of subcollections to retrieve. Optionally provide Firestore where() query constraints to apply to subcollection queries. Optionally limit the number of results and specify results sorting.
options.pagination: Specify a number of results per page. Optionally enable sorting of results. Optionally provide a cursor object for startAfter or endBefore.
options.noComputedFields: Exclude computed fields from the record.
options.noEmbeddingFields: Exclude embeddings fields from the record.
Returns
cursor: A cursor object that can be passed to startAfter or endBefore in options.pagination above.
pages: The number of pages returned.
docs: The results of the query.
subscribeOne
Add a listener to a record in the database.
(
path: string[],
docId: string,
callback: (docData: StokerRecord | undefined) => void,
errorCallback?: (error: Error) => void,
options?: {
only?: "cache" | "default";
relations?: boolean | {
fields: (string | CollectionField)[];
};
noComputedFields?: boolean;
noEmbeddingFields?: boolean;
}
) => Promise<() => void>
Parameters
path: The path to the collection for the record i.e. ["Clients"]. If the record is in a subcollection, the path will look more like ["Clients", "D89X6ZQ1sclE71BfsWmv", "Sites"].
docId: The id of the record to retrieve.
callback: Fires whenever the record or it relations are updated in the database.
errorCallback: Fires whenever the listener throw an error.
options.only: Only query the cache, or both the cache and the server (default).
options.relations: Include related records. Optionally specify a subset of relation fields to retrieve.
options.noComputedFields: Exclude computed fields from the record.
options.noEmbeddingFields: Exclude embeddings fields from the record.
Returns
An unsubscribe function.
subscribeMany
Add a listener to a collection in the database.
(
path: string[],
constraints: QueryConstraint[],
callback: (
docs: StokerRecord[],
cursor: Cursor,
metadata: SnapshotMetadata | undefined
) => void,
errorCallback?: (error: Error) => void,
options?: {
only?: "cache" | "default"
relations?:
| boolean
| {
fields: (string | CollectionField)[]
}
pagination?: {
number?: number
orderByField?: string | FieldPath
orderByDirection?: "asc" | "desc"
startAfter?: Cursor
endBefore?: Cursor
startAt?: Cursor
endAt?: Cursor
}
}
) => Promise<{
pages: number | undefined;
count: number | undefined;
unsubscribe: (direction?: "first" | "last") => void;
}>
Parameters
path: The path to the collection for the records i.e. ["Clients"]. If the records are in a subcollection, the path will look more like ["Clients", "D89X6ZQ1sclE71BfsWmv", "Sites"].
constraints: Provide Firestore where() query constraints to the query.
callback: Fires whenever the records or their relations are updated in the database. Returns the results of the query, a cursor that can be passed to startAt, endAt, startAfter or endBefore in options.pagination below and the Firestore snapshot metadata.
errorCallback: Fires whenever the listener throw an error.
options.only: Only query the cache, or both the cache and the server (default).
options.relations: Include related records. Optionally specify a subset of relation fields to retrieve.
options.pagination: Optionally specify a number of results per page. Optionally enable sorting of results. Optionally provide a cursor object for startAt, endAt, startAfter or endBefore.
Returns
pages: The number of pages returned.
count: The number of records returned.
unsubscribe: An unsubscribe function.
waitForPendingWrites
() => Promise<void>
Fires when all pending Firestore writes have persisted to the server.
getFiles
Retrieve a list of metadata objects for the files uploaded to a record.
(path: string, record: StokerRecord) => Promise<StorageItem[]>
Parameters
path: The path to the collection for the record to retrieve files for i.e. ["Clients"]. If the record is in a subcollection, the path will look more like ["Clients", "D89X6ZQ1sclE71BfsWmv", "Sites"].
record: The id of the record to retrieve files for.
Returns
An array of Firebase Storage items.
preloadCollection
Load or reload the preload cache for a collection.
(
collection: string,
constraints?: [string, WhereFilterOp, unknown][],
) => Promise<void>
sendMail
Send an email out of the system. You'll need to add Firestore Security Rules in firebase-rules/firestore.custom.rules.
(
to: string | string[],
subject: string,
text?: string,
html?: string,
cc?: string | string[],
bcc?: string | string[],
replyTo?: string,
attachments?: {
filename: string;
content: Buffer;
contentType: string;
}[],
from?: string
) => Promise<void>
sendAdminEmail
Send an email to the system administrator email defined in ADMIN_EMAIL in env/.env.
(
subject: string,
text?: string,
html?: string,
cc?: string | string[],
bcc?: string | string[],
replyTo?: string
) => Promise<void>
sendMessage
(to: string, body: string) => Promise<void>
Send an SMS out of the system. The to field must be a phone number starting with +. You'll need to add Firestore Security Rules in firebase-rules/firestore.custom.rules.
sendAdminSMS
(body: string) => Promise<void>
Send an SMS to the system administrator phone number defined in ADMIN_SMS in env/.env.
convertDataToTimezone
(date: Date) => DateTime<true> | DateTime<false>
Convert a JavaScript date to a Luxon DateTime object in you app's timezone.
convertTimestampToTimezone
(timestamp: Timestamp) => DateTime<true> | DateTime<false>
Convert a Firebase Timestamp to a Luxon DateTime object in your app's timezone.
keepTimezone
(date: Date, timezone: string) => Date
Set a Javascript date object to your app's timezone while keeping the current date and time.
removeTimezone
(date: Date, timezone: string) => Date
Set a Javascript date object to the user's local timezone while keeping the current date and time.
displayDate
(timestamp: Timestamp | FieldValue) => string
Display a Firebase Timestamp in the date format set in src/main.ts.
tryPromise
(configProperty: any, args?: unknown[]) => Promise<any>
A utility to get a Stoker config value. Provide the raw config value to configProperty. If the value is a function or a promise, add arguments to args. Returns a promise with the config value.
getCachedConfigValue
(config: GlobalConfig | CollectionCustomization, pathArray: ConfigPath, args?: unknown[], overwrite?: boolean) => Promise<any>
A utility to get a cached Stoker config value. Provide the config module to config. Provide a path to the config value, for example ["global", "auth", "enableMultiFactorAuth"] or ["collections", COLLECTION_NAME, "admin", "itemsPerPage"]. If the value is a function or a promise, provide an array of arguments to args. Set overwrite to true to ignore the currently cached value and re-generate the cached value.
getSchema
(operation: "create" | "update", collection: CollectionSchema, schema: CollectionsSchema) => ZodObject
Retrieve the Zod schema for a collection. Provide the operation, the collection's schema and the full app schema.
isDeleteSentinel
isDeleteSentinel: (value: any) => any
A helper to determine whether a value is a Firestore delete sentinel.